#include <iostream>
#include <fstream>
#include <sstream>
#include <CAENVMElib.h>
#include <TFile.h>
#include <TH1I.h>
using namespace std;

void quit();

int32_t handle;
int main(int argc, char** argv) {
	CVErrorCodes flag = CAENVME_Init(cvV1718, 0, 0, &handle);
	if (flag != cvSuccess)
		quit();

	unsigned int bufferOrg = 0x00;
	flag = CAENVME_WriteCycle(handle, 0x03210800c, &bufferOrg, cvA32_S_DATA, cvD32);
	if (flag != cvSuccess)
		quit();

	unsigned int triggers = 0x80000000;
	flag = CAENVME_WriteCycle(handle, 0x3210810c, &triggers, cvA32_S_DATA, cvD32);
	if (flag != cvSuccess)
		quit();

	unsigned int DAC[8] = { 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000 };
	for (int i = 0; i < 8; i++) {
		unsigned int address = 0x32101098 + i * 0x100;
		flag = CAENVME_WriteCycle(handle, address, &DAC[i], cvA32_S_DATA, cvD32);
		if (flag != cvSuccess)
			quit();
	}

	unsigned int turnRunOn = 0x4;
	flag = CAENVME_WriteCycle(handle, 0x32108100, &turnRunOn, cvA32_S_DATA, cvD32);
	if (flag != cvSuccess)
		quit();

	sleep(1);

	unsigned int trigger = 0x0;
	flag = CAENVME_WriteCycle(handle, 0x32108108, &trigger, cvA32_S_DATA, cvD32);
	if (flag != cvSuccess)
		quit();

	/*	int numCharsRequested = 2048;
	 int numCharsRetrieved = 1;
	 unsigned char* chars = new unsigned char[numCharsRequested + 1];
	 int totalCharsRetrieved = 0;
	 while (numCharsRetrieved > 0) {
	 flag = CAENVME_MBLTReadCycle(handle, 0x32100000, chars, numCharsRequested, cvA32_U_MBLT, &numCharsRetrieved);
	 chars[numCharsRetrieved] = '\0';
	 unsigned short temp = chars[0] + (chars[1] << 8);
	 cout << temp << endl;
	 }
	 delete[] chars;*/

	unsigned int numEventsInADC = 0;
	int lastEventsInBufferErrorTime = 0;
	flag = CAENVME_ReadCycle(handle, 0x3210812c, &numEventsInADC, cvA32_S_DATA, cvD32);
	if (flag != cvSuccess)
		quit();

	const int wordSize = 4194308;
	unsigned char** event = new unsigned char*[0];

	if (numEventsInADC > 0) {
		unsigned int status = 0;
		flag = CAENVME_ReadCycle(handle, 0x3210ef04, &status, cvA32_S_DATA, cvD32);
		if (flag != cvSuccess)
			quit();

		unsigned int ref = 1;
		bool bits[32];
		for (int i = 0; i < 32; i++)
			bits[i] = ((ref << i) & status);

		if (bits[0]) {
			int wordsRead = 0;
			int numBLT = 0;
			while (wordsRead < wordSize) {
				unsigned char** newEventTmp = new unsigned char*[numBLT + 1];
				for (int i = 0; i < numBLT; i++)
					newEventTmp[i] = event[i];
				delete event;
				event = newEventTmp;

				event[numBLT] = new unsigned char[2048];
				for (int i = 0; i < 2048; i++)
					event[numBLT][i] = 0xff;

				int numCharsRetrieved = 0;
				int numCharsRequested = 2048;
				int wordsLeft = wordSize - wordsRead;
				if (wordsLeft < 512)
					numCharsRequested = wordsLeft * 4;

				flag = CAENVME_MBLTReadCycle(handle, 0x32100000, event[numBLT], numCharsRequested, cvA32_U_MBLT,
						&numCharsRetrieved);
				if (flag != cvSuccess)
					quit();
				else {
					numBLT++;
					wordsRead += numCharsRetrieved / 4;
				}
			}

			unsigned char** newEventTmp = new unsigned char*[numBLT + 1];
			for (int i = 0; i < numBLT; i++)
				newEventTmp[i] = event[i];
			delete event;
			newEventTmp[numBLT] = NULL;
			event = newEventTmp;
		}
	}
	cout << "blah" << endl;

	TFile* file = new TFile("output.root", "update");
	int i;
	for (i = 0; true; i++) {
		stringstream runTempSS;
		runTempSS << "run" << i;

		TH1I* test = (TH1I*) file->Get(runTempSS.str().c_str());
		if (test == NULL)
			break;
	}
	stringstream runSS;
	runSS << "run" << i;

	TH1I* histo = new TH1I(runSS.str().c_str(), "Big Sample Read;sample,value", 0x100000, -0.5, 0x100000 - 0.5);

	for (i = 0; i < 0x100000; i++) {
		int j = 7;
		int posWithHeader = i * 2 + j * 2097152 + 16;
		int blt = (int) posWithHeader / 2048;
		int pos = posWithHeader % 2048;
		//			data[j][i] = (unsigned short) event[blt][pos] + (unsigned short) ((event[blt][pos + 1] & 0xf) << 8);
		histo->Fill(i, (unsigned short) event[blt][pos] + (unsigned short) ((event[blt][pos + 1] & 0xf) << 8));
	}

	//	for (i = 0; event[i]; i++)
	//		delete event[i];
	//	delete event;

	histo->Write();
	file->Close();

	unsigned int turnRunOff = 0x0;
	CAENVME_WriteCycle(handle, 0x32108100, &turnRunOff, cvA32_S_DATA, cvD32);
	CAENVME_End(handle);
	return 0;
}

void quit() {
	cout << "Quitting prematurely" << endl;
	unsigned int turnRunOff = 0x0;
	CAENVME_WriteCycle(handle, 0x32108100, &turnRunOff, cvA32_S_DATA, cvD32);
	CAENVME_End(handle);
	exit(0);
}
